package com.zm.xiaohashu.search.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
import com.zm.constant.DateConstants;
import com.zm.response.PageResponse;
import com.zm.utils.DateUtils;
import com.zm.utils.NumberUtils;
import com.zm.xiaohashu.search.enums.NotePublishTimeRangeEnum;
import com.zm.xiaohashu.search.enums.NoteSortTypeEnum;
import com.zm.xiaohashu.search.index.NoteIndex;
import com.zm.xiaohashu.search.model.SearchNoteReqVO;
import com.zm.xiaohashu.search.model.SearchNoteRspVO;
import com.zm.xiaohashu.search.service.NoteService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@RequiredArgsConstructor
@Service
@Slf4j
public class NoteServiceImpl implements NoteService {
    private final RestHighLevelClient restHighLevelClient;

    @Override
    public PageResponse<SearchNoteRspVO> searchNote(SearchNoteReqVO searchNoteReqVO) {
        String keyword = searchNoteReqVO.getKeyword();
        // 笔记类型
        Integer type = searchNoteReqVO.getType();
        Integer sortType = searchNoteReqVO.getSort();
        Integer pageNo = searchNoteReqVO.getPageNo();

        SearchRequest searchRequest = new SearchRequest(NoteIndex.NAME);
        // 创建查询构建器
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 创建查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();


        if (Objects.nonNull(keyword)&& StrUtil.isNotBlank( keyword)){
            boolQueryBuilder.must(QueryBuilders.matchQuery(NoteIndex.FIELD_NOTE_TITLE, keyword));
        }else {
            //查全部
            boolQueryBuilder.must(QueryBuilders.matchAllQuery());
        }
        if (Objects.nonNull(type)) {
            log.info("==> 笔记类型: {}", type);
            boolQueryBuilder.filter(QueryBuilders.termQuery(NoteIndex.FIELD_NOTE_TYPE, type));
        }
        if (Objects.nonNull(sortType)) {
            log.info("==> 笔记排序: {}", sortType);
            NoteSortTypeEnum noteSortTypeEnum = NoteSortTypeEnum.valueOf(sortType);
            switch (noteSortTypeEnum) {
                case LATEST -> sourceBuilder.sort(NoteIndex.FIELD_NOTE_UPDATE_TIME, SortOrder.DESC);
                case MOST_LIKE -> sourceBuilder.sort(NoteIndex.FIELD_NOTE_LIKE_TOTAL, SortOrder.DESC);
                case MOST_COMMENT -> sourceBuilder.sort(NoteIndex.FIELD_NOTE_COMMENT_TOTAL, SortOrder.DESC);
            }
        }
        //按照时间
        // 发布时间范围
        Integer publishTimeRange = searchNoteReqVO.getPublishTimeRange();
        log.info("==> 笔记发布时间范围: {}", publishTimeRange);
        if (Objects.nonNull(publishTimeRange)){
            // 结束时间(今天的时间)
            String endTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern(DateConstants.DATE_FORMAT_Y_M_D_H_M_S));
            // 开始时间
            String startTime = null;
            NotePublishTimeRangeEnum notePublishTimeRangeEnum = NotePublishTimeRangeEnum.valueOf(publishTimeRange);
            switch (notePublishTimeRangeEnum){
                case DAY -> startTime = LocalDateTime.now().minusDays(1).format(DateTimeFormatter.ofPattern(DateConstants.DATE_FORMAT_Y_M_D_H_M_S));
                case WEEK -> startTime = LocalDateTime.now().minusWeeks(1).format(DateTimeFormatter.ofPattern(DateConstants.DATE_FORMAT_Y_M_D_H_M_S));
                case HALF_YEAR -> startTime = LocalDateTime.now().minusMonths(6).format(DateTimeFormatter.ofPattern(DateConstants.DATE_FORMAT_Y_M_D_H_M_S));
            }
            log.info("==> 笔记发布时间范围: {}", startTime);
            boolQueryBuilder.filter(QueryBuilders.rangeQuery(NoteIndex.FIELD_NOTE_UPDATE_TIME).lte(endTime).gte(startTime));
        }

        int pageSize = 10; // 每页展示数据量
        int from = (pageNo - 1) * pageSize; // 偏移量
        sourceBuilder.from(from);
        sourceBuilder.size(pageSize);
        // 设置高亮字段
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field(NoteIndex.FIELD_NOTE_TITLE)
                .preTags("<strong>") // 设置包裹标签
                .postTags("</strong>");
        sourceBuilder.highlighter(highlightBuilder);
        sourceBuilder.query(boolQueryBuilder);

        // 将构建的查询条件设置到 SearchRequest 中
        searchRequest.source(sourceBuilder);
        // 返参 VO 集合
        List<SearchNoteRspVO> searchNoteRspVOS = null;
        // 总文档数，默认为 0
        long total = 0;
        try {
            log.info("==> SearchRequest: {}", searchRequest);
            // 执行搜索
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            // 处理搜索结果
            total = searchResponse.getHits().getTotalHits().value;
            log.info("==> 命中文档总数, hits: {}", total);

            searchNoteRspVOS = Lists.newArrayList();

            // 获取搜索命中的文档列表
            SearchHits hits = searchResponse.getHits();

            for (SearchHit hit : hits) {
                log.info("==> 文档数据: {}", hit.getSourceAsString());

                // 获取文档的所有字段（以 Map 的形式返回）
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();

                // 提取特定字段值
                Long noteId = (Long) sourceAsMap.get(NoteIndex.FIELD_NOTE_ID);
                String cover = (String) sourceAsMap.get(NoteIndex.FIELD_NOTE_COVER);
                String title = (String) sourceAsMap.get(NoteIndex.FIELD_NOTE_TITLE);
                String avatar = (String) sourceAsMap.get(NoteIndex.FIELD_NOTE_AVATAR);
                String nickname = (String) sourceAsMap.get(NoteIndex.FIELD_NOTE_NICKNAME);
                // 获取更新时间
                String updateTimeStr = (String) sourceAsMap.get(NoteIndex.FIELD_NOTE_UPDATE_TIME);
                LocalDateTime updateTime = LocalDateTime.parse(updateTimeStr, DateTimeFormatter.ofPattern(DateConstants.DATE_FORMAT_Y_M_D_H_M_S));
                Integer likeTotal = (Integer) sourceAsMap.get(NoteIndex.FIELD_NOTE_LIKE_TOTAL);

                // 获取高亮字段
                String highlightedTitle = null;
                if (CollUtil.isNotEmpty(hit.getHighlightFields())
                        && hit.getHighlightFields().containsKey(NoteIndex.FIELD_NOTE_TITLE)) {
                    highlightedTitle = hit.getHighlightFields().get(NoteIndex.FIELD_NOTE_TITLE).fragments()[0].string();
                }

                // 构建 VO 实体类
                SearchNoteRspVO searchNoteRspVO = SearchNoteRspVO.builder()
                        .noteId(noteId)
                        .cover(cover)
                        .title(title)
                        .highlightTitle(highlightedTitle)
                        .avatar(avatar)
                        .nickname(nickname)
                        .updateTime(DateUtils.formatRelativeTime(updateTime))
                        .likeTotal(NumberUtils.formatNumberString(likeTotal))
                        .build();
                searchNoteRspVOS.add(searchNoteRspVO);
            }
        } catch (IOException e) {
            log.error("==> 查询 Elasticserach 异常: ", e);
        }

        return PageResponse.success(searchNoteRspVOS, pageNo, total);
    }
}
